import controlP5.*;
import org.json.simple.JSONObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


ControlP5 cp5;
controlP5.Button btPrev, btNext, btRotLeft, btRotRight;
Toggle btPlay;
MultiList andrVers, mainMenu;
MultiListButton btMulti, btMenu;
Textlabel lbVers;
int col, currVers;
long currentTime;
boolean PlayPause = false;
String[] vers = {"1.5_r4", "1.6_r2", "2.0_r1", "2.1_r2", "2.2_r1.1", "2.2.1_r1", "2.2.2_r1", "2.3_r1", "2.3.1_r1", "2.3.2_r1", 
              "2.3.3_r1", "2.3.4_r1", "2.3.5_r1", "2.3.6_r1", "2.3.7_r1", "4.0.1_r1", "4.0.2_r1", "4.0.3_r1", "4.0.4_r1.2", 
              "4.0.4_r2.1", "4.1.1_r1", "4.1.2_r1", "4.2_r1", "4.2.1_r1.2", "4.2.2_r1", "4.3_r1", "4.3_r2.1"};
Map <JSONObject, List<JSONObject>> infoMap;
DataProcessor dP;
VisualizationBuilder vB;

//List of files to be inserted into visualisation
String[] pkgFileNameGR = {"graphics/Color.java","graphics/NinePatch.java","graphics/Insets.java", "graphics/TypeFace.java", "graphics/TypeFaceTest.java", "graphics/Movie.java", "graphics/LargeBitmap.java", "graphics/Canvas.java", "graphics/Camera.java"};
String[] pkgFileName = {"os/Parcel.java", "os/Message.java", "os/UEventObserver.java", "os/Process.java"};
int div = 0;

//Create all GUI elements(buttons, background, etc.)
void setup() {
  size(1280, 800, P3D);
  smooth();
  background(loadImage("wallpaper.jpg")); 
  cp5 = new ControlP5(this);
  infoMap = new HashMap<JSONObject, List<JSONObject>> ();
  dP = new DataProcessor();
  vB = new VisualizationBuilder();
  
  //Initialize buttons and label
  btPlay = cp5.addToggle("PlayPause")
              .setPosition(20,750)
              .setSize(100,30);
  
  btPrev = cp5.addButton("Previous")
              .setPosition(140,750)
              .setSize(100,30);

  btNext = cp5.addButton("Next")
              .setPosition(260,750)
              .setSize(100,30);
              
  btRotLeft = cp5.addButton("Rotate Left")
                 .setPosition(380,750)
                 .setSize(100,30);
                
  btRotRight = cp5.addButton("Rotate Right")
                 .setPosition(500,750)
                 .setSize(100,30); 
                 
  lbVers = cp5.addTextlabel("Version Label")
              .setText("HELLO!")
              .setPosition(620,750)
              .setFont(createFont("Impact",20));
              
  //Initialize main menu           
  mainMenu = cp5.addMultiList("Main Menu", 20, 100, 100, 25);
  
  btMenu = mainMenu.add("Menu", 1);
  btMenu.add("Start Demo", 11);
  
  //Initialize versions list
  andrVers = cp5.addMultiList("Android Version", 20, 200, 100, 25); 
  
  btMulti = andrVers.add("1.x", 1);
  for(int i=0; i<2; i++) {
    btMulti.add(vers[i], i);
  }
  
  btMulti = andrVers.add("2.x", 2);
  for(int i=2; i<15; i++) {
    btMulti.add(vers[i], i);
  }
  
  btMulti = andrVers.add("3.x", 3);
  btMulti.add("N/A", 31);

  btMulti = andrVers.add("4.x", 4);
  for(int i=15; i<27; i++) {
    btMulti.add(vers[i], i);
  }
  
  //Initialize disable button func
  col = btPlay.getColor().getBackground();
  setLock(btPlay, true);
  setLock(btPrev, true);
  setLock(btNext, true);
  setLock(btRotLeft, true);
  setLock(btRotRight, true);
  
  btPlay.hide();
}

void draw() {
}

//Disables buttons 
void setLock(Controller cont, boolean val) {
  cont.setLock(val);
  if(val) {
    cont.setColorBackground(color(100,100));
  } else {
    cont.setColorBackground(color(col));
  }
}

//Disables buttons using setLock when reaching the beginning or end
void lockCheck(int currVers) {
  if(currVers == 0) {
    setLock(btPrev, true);
    setLock(btNext, false);
  } 
  else if(currVers == vers.length - 1) {
    setLock(btPrev, false);
    setLock(btNext, true);
  }
  else {
    setLock(btPrev, false);  
    setLock(btNext, false);
  }
}

//Updates the label to the current Android versions
void updateLabel(int currVers) {
  if(currVers == 0) {
    lbVers.setText(vers[currVers].toUpperCase());
  }
  else {
    lbVers.setText(vers[currVers-1].toUpperCase() + " - " + vers[currVers].toUpperCase());  
  }
}

//Triggers when GUI elements are clicked
void controlEvent(ControlEvent theEvent) {
  String cltrName = theEvent.getController().getName();
  
  if(cltrName.equals("PlayPause")) {
    if(PlayPause) {
      for(int i=currVers; i<vers.length; i++) {
        currVers++;
        generateModel(vers[currVers], pkgFileName);
        if(i!=vers.length-1) {
          currentTime = millis(); 
          while( millis() - currentTime < 2000 ) { 
          }
        }
      }
    }
    else { 
    }
  }
  else if(cltrName.equals("Previous")) {
    currVers--;
    generateModel(vers[currVers], pkgFileName);
  }
  else if(cltrName.equals("Next")) {
    currVers++;
    generateModel(vers[currVers], pkgFileName);
  }
  else if(cltrName.equals("Rotate Left")) {
    pushMatrix();
    translate(700,0,-150);
    div = div - 1;
    rotateY(div);
    translate(-700,0,150);
    generateModel(vers[currVers], pkgFileName);
    popMatrix();
  }
  else if(cltrName.equals("Rotate Right")) {
    pushMatrix();
    translate(700,0,-150);
    div = div + 1;
    rotateY(div);
    translate(-700,0,150);
    generateModel(vers[currVers], pkgFileName);
    popMatrix();
  }
  else if(cltrName.equals("Start Demo")) {
    currVers = 0;
    setLock(btPlay, false);
    setLock(btRotLeft, false);
    setLock(btRotRight, false);
    generateModel(vers[currVers], pkgFileName);
  }
  else if(cltrName.contains("_r")) {
    for(int i=0; i<vers.length; i++) {
      if(cltrName.equals(vers[i])) {
        currVers = i;
        generateModel(vers[currVers], pkgFileName);
        break;
      }  
    }
  }
}

//Called from controlElement; calls VisualizationBuilder and passes data for model generation
void generateModel(String versNum, String[] pkgFileName) {
  background(loadImage("wallpaper.jpg")); 
  lockCheck(currVers);
  updateLabel(currVers);
  vB.drawDistrict(color(19,63,100));
  
  //For each class file
  for( int i = 0; i < pkgFileName.length; i++ ) {
    infoMap = dP.getClassMethodLineNumbers(versNum + "/android/" + pkgFileName[i]);
    //Gets the class information
    JSONObject classInfo = infoMap.keySet().iterator().next();
    //Gets the function data for the class
    List<JSONObject> entry = infoMap.values().iterator().next();
    vB.drawBuilding((Integer) classInfo.get("Class Count"), entry, 2);
  }
}
